//School of Informatics Xiamen University, GPL-3.0 license
package cn.edu.xmu.javaee.productdemojpa.dao;


import cn.edu.xmu.javaee.core.bean.RequestVariables;
import cn.edu.xmu.javaee.core.exception.BusinessException;
import cn.edu.xmu.javaee.core.model.ReturnNo;
import cn.edu.xmu.javaee.core.model.UserToken;
import cn.edu.xmu.javaee.core.util.JacksonUtil;
import cn.edu.xmu.javaee.productdemojpa.config.ApplicationConfig;
import cn.edu.xmu.javaee.productdemojpa.dao.bo.Product;
import cn.edu.xmu.javaee.productdemojpa.mapper.separate.ProductPoMapper;
import cn.edu.xmu.javaee.productdemojpa.mapper.separate.po.ProductPo;

import cn.edu.xmu.javaee.productdemojpa.util.CloneFactory;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.MessageSource;
import org.springframework.dao.DataAccessException;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import java.util.*;

import static cn.edu.xmu.javaee.core.model.Constants.PLATFORM;
/**
 * @author Ming Qiu
 **/
@Repository
@Slf4j
@RequiredArgsConstructor
public class ProductDao implements FindProduct,InitializingBean {

    private final ProductPoMapper productPoMapper;
    private final MessageSource messageSource;
    private final RequestVariables requestVariables;
    private final ApplicationConfig applicationConfig;
    private final ApplicationContext applicationContext;

    private FindProduct findProduct;

    /**
     * 用名称寻找Product对象
     *
     * @param name 名称
     * @return Product对象列表，带关联的Product返回
     */
    public List<Product> retrieveSimpleProductByName(Long shopId, String name) throws BusinessException {
        List<Product> productList = new ArrayList<>();
        try {
            List<ProductPo> productPoList;
            Pageable pageable = PageRequest.of(1, 100);
            if (PLATFORM.equals(shopId)){
                productPoList = this.productPoMapper.findByName(name, pageable);
            } else {
                productPoList = this.productPoMapper.findByShopIdAndName(shopId, name, pageable);
            }
            for (ProductPo po : productPoList) {
                Product product = CloneFactory.copy(new Product(), po);
                productList.add(product);
            }
            log.debug("retrieveSimpleProductByName: productList = {}", productList);
        } catch (DataAccessException e) {
            log.error(e.getMessage());
            throw new BusinessException(ReturnNo.INTERNAL_SERVER_ERR, e.getMessage());
        }

        return productList;
    }

    /**
     * 用id对象找Product对象
     *
     * @param shopId 商铺id
     * @param productId 产品id
     * @return Product对象，不关联的Product
     */
    public Product findSimpleProductById(Long shopId, Long productId) throws BusinessException {
        Product product = null;
        try {
            ProductPo productPo = this.findPoById(shopId,productId);
            product = CloneFactory.copy(new Product(), productPo);
            log.debug("findSimpleProductById: product = {}", product);
        } catch (DataAccessException e) {
            log.error(e.getMessage());
            throw new BusinessException(ReturnNo.INTERNAL_SERVER_ERR, e.getMessage());
        }
        return product;
    }

    /**
     * 创建Product对象
     *
     * @param product 传入的Product对象
     * @return 返回对象ReturnObj
     */
    public Product insert(Product product) throws BusinessException {

        Product retObj = null;
        try {
            ProductPo po = CloneFactory.copy(new ProductPo(), product);
            log.debug("insert: po = {}", po);
            ProductPo ret = this.productPoMapper.save(po);
            retObj = CloneFactory.copy(new Product(), ret);
        } catch (DataAccessException e) {
            log.error(e.getMessage());
            throw new BusinessException(ReturnNo.INTERNAL_SERVER_ERR, e.getMessage());
        }
        return retObj;
    }

    /**
     * 修改商品信息
     *
     * @param product 传入的product对象
     * @return void
     */
    public void update(Product product) throws BusinessException {
        UserToken userToken = this.requestVariables.getUser();
        try {
            log.debug("update:  product = {}",  product);
            ProductPo oldPo = this.findPoById(userToken.getDepartId(), product.getId());
            if (Objects.nonNull(product.getName())){
                oldPo.setName(product.getName());
            }

            if (Objects.nonNull(product.getBarcode())){
                oldPo.setBarcode(product.getBarcode());
            }

            if (Objects.nonNull(product.getShopId())){
                oldPo.setShopId(product.getShopId());
            }

            if (Objects.nonNull(product.getOriginalPrice())){
                oldPo.setOriginalPrice(product.getOriginalPrice());
            }

            if (Objects.nonNull(product.getCommissionRatio())){
                oldPo.setCommissionRatio(product.getCommissionRatio());
            }

            this.productPoMapper.save(oldPo);
        } catch (DataAccessException e) {
            log.error(e.getMessage());
            throw new BusinessException(ReturnNo.INTERNAL_SERVER_ERR, e.getMessage());
        }
    }

    /**
     * 删除商品
     *
     * @param id 商品id
     * @return
     */
    public void delete(Long id) throws BusinessException {
        try {
            UserToken userToken = this.requestVariables.getUser();
            this.findPoById(userToken.getDepartId(), id);
            this.productPoMapper.deleteById(id);
        } catch (DataAccessException e) {
            log.error(e.getMessage());
            throw new BusinessException(ReturnNo.INTERNAL_SERVER_ERR, e.getMessage());
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        String daoBean = this.applicationConfig.getJpa();
        this.findProduct = applicationContext.getBean(daoBean, FindProduct.class);
    }

    @Override
    public Product findById(Long shopId,Long productId) throws BusinessException {
        return this.findProduct.findById(shopId, productId);
    }

    @Override
    public List<Product> retrieveByName(Long shopId, String name) throws BusinessException {
        return this.findProduct.retrieveByName(shopId, name);
    }

    /**
     * 找到po对象，判断对象是否存在以及是否属于本商铺
     * @param shopId 商铺id
     * @param productId 商品id
     * @return RESOURCE_ID_OUTSCOPE, RESOURCE_ID_NOTEXIST
     */
    private ProductPo findPoById(Long shopId, Long productId){
        Locale locale = this.requestVariables.getLocale();
        Optional<ProductPo> ret = this.productPoMapper.findById(productId);
        ProductPo productPo = ret.orElseThrow(() ->
                 new BusinessException(ReturnNo.RESOURCE_ID_NOTEXIST, JacksonUtil.toJson(new String[] {messageSource.getMessage("product", null, locale), productId.toString()})));
        log.debug("findPoById: shopId = {}, productPo = {}", shopId, productPo);
        if (!Objects.equals(shopId, productPo.getShopId()) && !PLATFORM.equals(shopId)){
            String[] objects = new String[] {messageSource.getMessage("product", null, locale), productId.toString(), shopId.toString()};
            throw new BusinessException(ReturnNo.RESOURCE_ID_OUTSCOPE, JacksonUtil.toJson(objects));
        }
        return productPo;
    }
}
